﻿// Copyright (c) 2013, Simon Carter.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted 
// provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this list of 
//   conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice, this list of 
//  conditions and the following disclaimer in the documentation and/or other materials provided 
//  with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// History
// Initial Release - Simon Carter
//

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
using System.Diagnostics;
using System.Windows.Forms;
using System.Threading;
using System.IO;
using System.Text.RegularExpressions;

using ErrorManager.ErrorClient;
using ErrorManager.ErrorClient.Classes;

namespace ErrorManager.ErrorClient.Forms
{
    public partial class ErrorHandlerForm : Form
    {
        #region Private Members

        private bool _forceSend;
        private Exception _error;
        private Options _options;
        private DisplayOptions _displayOptions;
        private string _screenPicture;
        private string _loadedModules;

        #endregion Private Members

        #region Constructors

        public ErrorHandlerForm(Options options, Exception error, bool forceSendData)
        {
            CaptureScreen();

            InitializeComponent();

            _error = error;
            lblError.Text = error.Message;
            _options = options;


            ErrorClient.GetErrorClient.OnProgress += _errClient_OnProgress;
            ErrorClient.GetErrorClient.AdditionalFiles += GetErrorClient_ExtraFiles;

            _forceSend = forceSendData;          
        }

        void GetErrorClient_ExtraFiles(object sender, AdditionalFilesEventArgs e)
        {
            e.Files.Add(_screenPicture);
        }

        #endregion Constructors

        #region Static Methods

        public static bool DisplayErrorDetails(DisplayOptions displayOptions, Options options, Exception error)
        {
            bool Result = false;

            ErrorHandlerForm frm = new ErrorHandlerForm(options, error, displayOptions.ForceSendData);
            frm.Text = String.IsNullOrEmpty(displayOptions.Title) ? frm.Text : displayOptions.Title;
            frm.Icon = displayOptions.FormIcon;
            frm.btnSend.Enabled = !displayOptions.ForceSendData;
            frm.lblSendMessage.Visible = false;
            frm.lblSendInfo.Visible = false;
            frm.lblSendInformation.Enabled = !displayOptions.ForceSendData;
            frm.btnNo.Enabled = !displayOptions.ForceSendData;
            frm.btnYes.Enabled = !displayOptions.ForceSendData;
            frm.TopMost = displayOptions.FormOnTop;

            if (!displayOptions.AllowContinue)
            {
                frm.lblMainMessage.Text = "An unhandled error occured";
                frm.btnYes.Enabled = false;
            }

            frm._displayOptions = displayOptions;

            if (displayOptions.FormIcon == null)
                frm.ShowIcon = false;
            else
                frm.Icon = displayOptions.FormIcon;

            Result = frm.ShowDialog() == DialogResult.Yes;

            return (Result);
        }

        #endregion Static Methods

        #region Private Methods

        private void _errClient_OnProgress(object sender, ProgressEventArgs e)
        {
            if (this.InvokeRequired)
            {
                ProgressHandler ph = new ProgressHandler(_errClient_OnProgress);
                this.Invoke(ph, new object[] { sender, e });
            }
            else
            {
                if (e.Stage == ProcessStage.Waiting)
                {
                    Application.DoEvents();
                }
                else
                {
                    if (!lblSendMessage.Visible)
                        lblSendMessage.Visible = true;

                    if (!lblSendInfo.Visible)
                        lblSendInfo.Visible = true;

                    lblSendMessage.Text = SplitCamelCase(e.Stage.ToString());

                    if (e.Stage == ProcessStage.SendingFile || e.Stage == ProcessStage.FileSent)
                        lblSendInfo.Text = System.IO.Path.GetFileName(e.Information);
                    else
                        lblSendInfo.Text = SplitCamelCase(e.Information);

                    Application.DoEvents();
                    System.Threading.Thread.Sleep(100);
                }
            }
        }

        private void CaptureScreen()
        {
            try
            {
                ScreenCapture sc = new ScreenCapture();
                // capture this window, and save it
                _screenPicture = Path() + "ScreenShot.gif";

                sc.CaptureScreenToFile(_screenPicture, ImageFormat.Gif);
            }
            catch (Exception err)
            {
                MessageBox.Show(String.Format("Unable to capture screen\r\n{0}", err.Message));
            }
        }

        private void LoadedModules()
        {
            _loadedModules = Path() + "LoadedModules.dat";

            StreamWriter sw = new StreamWriter(_loadedModules);
            try
            {
                foreach (ProcessModule processModule in Process.GetCurrentProcess().Modules)
                {
                    sw.WriteLine(String.Format("{0} - Version: {1}\r\n", processModule.FileName, processModule.FileVersionInfo.FileVersion.ToString()));
                }

                sw.Flush();
            }
            finally
            {
                sw.Close();
                sw = null;
            }

        }

        private void ErrorHandlerForm_Shown(object sender, EventArgs e)
        {
            ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(ForceSend));
        }

        private delegate void ForceSendDelgate(object state);
        private void ForceSend(object state)
        {
            if (this.InvokeRequired)
            {
                ForceSendDelgate ph = new ForceSendDelgate(ForceSend);
                this.Invoke(ph, new object[] { state });
            }
            else
            {
                SendDataToServer();
            }
        }

        private string Path()
        {
            string Result = System.Reflection.Assembly.GetExecutingAssembly().CodeBase;
            Result = System.IO.Path.GetDirectoryName(Result);
            Result = Result.Substring(6);

            return (Result);
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            SendDataToServer();
        }

        private void SendDataToServer()
        {
            btnNo.Enabled = false;
            btnYes.Enabled = false;
            btnSend.Enabled = false;
            lblSendInformation.Enabled = false;
            try
            {
                bool dataSent = ErrorClient.GetErrorClient.SendError(
                    _options,
                    String.Format("{0}\rn\r\n{1}", _error.Message, _error.StackTrace.ToString()));
            }
            finally
            {
                btnNo.Enabled = true;
                btnYes.Enabled = _displayOptions.AllowContinue;
            }
        }

        private string SplitCamelCase(string s)
        {
            var r = new Regex(@"
                (?<=[A-Z])(?=[A-Z][a-z]) |
                 (?<=[^A-Z])(?=[A-Z]) |
                 (?<=[A-Za-z])(?=[^A-Za-z])", RegexOptions.IgnorePatternWhitespace);

            return (r.Replace(s.Replace("_", ""), " "));
        }

        #endregion Private Methods

    }
}
